home *** CD-ROM | disk | FTP | other *** search
- Subject: v12i008: Cake, a make replacement, Part02/09
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rs@uunet.UU.NET
-
- Submitted-by: Zoltan Somogyi <zs@munnari.oz>
- Posting-number: Volume 12, Issue 8
- Archive-name: cake/part02
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # act.c
- # chase.c
- # entry.c
- # error.c
- # expand.c
- # file.c
- # This archive created: Wed Oct 14 21:08:43 1987
- export PATH; PATH=/bin:/usr/bin:$PATH
- echo shar: "extracting 'act.c'" '(12578 characters)'
- if test -f 'act.c'
- then
- echo shar: "will not over-write existing file 'act.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'act.c'
- X/*
- X** Module to execute Cake actions.
- X*/
- X
- Xstatic char
- Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/act.c,v 1.14 86/07/19 12:22:18 zs Exp $";
- X
- X#include "cake.h"
- X
- X/*
- X** Update the node by executing the attached actions.
- X** Actually, all the buddies will be updated, and
- X** no action will be executed unless it is necessary.
- X**
- X** The level of a file is one greater than the level of its
- X** parent in the chase graph; the level of !MAINCAKE! is 0.
- X** This controls the printing of messages about the primary
- X** targets.
- X*/
- X
- Xupdate(node, level, force_exec)
- Xreg Node *node;
- Xreg int level;
- Xreg bool force_exec;
- X{
- X extern get_utime();
- X extern save_novol();
- X extern bool diff_novol();
- X extern Wait carry_out();
- X extern char *list_names();
- X reg Node *bnode, *onode;
- X reg List *ptr, *ptr1;
- X reg bool oksofar, needact, mayskip;
- X reg List *errnodes;
- X Wait code;
- X
- X put_trail("update", "start");
- X cdebug("hunting %s at level %d\n", node->n_name, level);
- X
- X /* force printing of "up-to-date" messages */
- X if (level == 0 && is_ok(node))
- X node->n_kind = n_CANDO;
- X
- X if (off_node(node, nf_ERR) && is_ok(node))
- X {
- X cdebug("everything a-ok, nothing to do\n");
- X if (level == 1)
- X {
- X if (on_node(node, nf_ORIG))
- X {
- X printf("cake: target %s has no ancestors\n", node->n_name);
- X node->n_kind = n_NOWAY;
- X }
- X or (! xflag)
- X printf("cake: %s is up to date\n", node->n_name);
- X }
- X
- X put_trail("update", "finish");
- X return;
- X }
- X
- X#ifdef CAKEDEBUG
- X if (cakedebug)
- X {
- X printf("starting update of\n");
- X print_node(node);
- X }
- X#endif
- X
- X if (on_node(node, nf_ERR))
- X {
- X trace_errs(node);
- X return;
- X }
- X
- X errnodes = NULL;
- X
- X /* skip the actions if they are useless or not needed */
- X oksofar = TRUE;
- X needact = FALSE;
- X mayskip = FALSE;
- X for_list (ptr, node->n_new)
- X {
- X bnode = (Node *) ldata(ptr);
- X
- X if (on_node(bnode, nf_ERR))
- X {
- X oksofar = FALSE;
- X errnodes = addtail(errnodes, bnode);
- X }
- X else
- X {
- X if (off_node(bnode, nf_EXIST) || bnode->n_rtime < bnode->n_utime)
- X needact = TRUE;
- X
- X if (on_node(bnode, nf_DEPNONVOL))
- X mayskip = TRUE;
- X }
- X }
- X
- X if (! oksofar)
- X {
- X cdebug("error in buddies\n");
- X if (vflag && strdiff(node->n_name, CHASEROOT))
- X {
- X sprintf(scratchbuf, "cannot proceed with update of %s because of problems with %s %s",
- X node->n_name, (length(errnodes) == 1)? "buddy": "buddies", list_names(errnodes));
- X add_error(node, new_name(scratchbuf), errnodes, TRUE);
- X trace_errs(node);
- X }
- X
- X goto endit;
- X }
- X
- X if (! needact)
- X {
- X cdebug("no need for actions\n");
- X if (strdiff(node->n_name, CHASEROOT))
- X printf("cake: %s is up to date\n", node->n_name);
- X
- X goto endit;
- X }
- X
- X /* update all ancestors of all buddies */
- X for_list (ptr, node->n_new)
- X {
- X bnode = (Node *) ldata(ptr);
- X for_list (ptr1, bnode->n_old)
- X {
- X onode = (Node *) ldata(ptr1);
- X update(onode, level+1, force_exec);
- X if (on_node(onode, nf_ERR) || ! is_ok(onode))
- X {
- X oksofar = FALSE;
- X errnodes = addtail(errnodes, onode);
- X }
- X }
- X }
- X
- X /* skip the actions if any ancestors are missing */
- X if (! oksofar)
- X {
- X cdebug("error in prerequisites\n");
- X if (vflag && strdiff(node->n_name, CHASEROOT))
- X {
- X sprintf(scratchbuf, "cannot proceed with update of %s because of problems with %s %s",
- X node->n_name, (length(errnodes) == 1)? "ancestor": "ancestors", list_names(errnodes));
- X add_error(node, new_name(scratchbuf), errnodes, TRUE);
- X trace_errs(node);
- X }
- X
- X goto endit;
- X }
- X
- X /* skip the actions; node is a missing base file */
- X if (is_noway(node))
- X {
- X cdebug("error in planning\n");
- X trace_errs(node);
- X goto endit;
- X }
- X
- X /* find any NOWAY buddies; these may have n_old == [] */
- X for_list (ptr, node->n_new)
- X {
- X bnode = (Node *) ldata(ptr);
- X if (is_noway(bnode))
- X {
- X oksofar = FALSE;
- X errnodes = addtail(errnodes, bnode);
- X }
- X }
- X
- X /* skip the actions if there are any NOWAY buddies */
- X if (! oksofar)
- X {
- X cdebug("error in buddy planning\n");
- X sprintf(scratchbuf, "dare not update %s because of possible effects on %s %s", node->n_name,
- X (length(errnodes) == 1)? "buddy": "buddies", list_names(errnodes));
- X add_error(node, new_name(scratchbuf), LNULL, TRUE);
- X trace_errs(node);
- X goto endit;
- X }
- X
- X /* reevaluate the necessity to act in the light of the */
- X /* actions taken to update possibly nonvolatile ancestors */
- X if (mayskip)
- X {
- X needact = FALSE; /* assume so for the moment */
- X cdebug("deciding whether to skip\n");
- X for_list (ptr, node->n_new)
- X {
- X bnode = (Node *) ldata(ptr);
- X
- X if (on_node(bnode, nf_DEPNONVOL))
- X {
- X cdebug("considering %s\n", bnode->n_name);
- X get_utime(bnode, FALSE);
- X }
- X
- X if (off_node(bnode, nf_EXIST) || bnode->n_rtime < bnode->n_utime)
- X {
- X cdebug("%s needs action\n", bnode->n_name);
- X needact = TRUE;
- X }
- X }
- X }
- X
- X if (! needact)
- X {
- X cdebug("no need for actions after all\n");
- X if (strdiff(node->n_name, CHASEROOT))
- X printf("cake: %s is up to date\n", node->n_name);
- X
- X goto endit;
- X }
- X
- X if (tflag)
- X {
- X /* instead of action just touch the targets */
- X for_list (ptr, node->n_new)
- X {
- X bnode = (Node *) ldata(ptr);
- X if (on_node(bnode, nf_PSEUDO))
- X continue;
- X
- X if (rflag)
- X cake_utimes(bnode, bnode->n_utime);
- X else
- X cake_utimes(bnode, GENESIS);
- X
- X printf("touch %s\n", bnode->n_name);
- X }
- X }
- X else
- X {
- X /* prepare for actions */
- X for_list (ptr, node->n_new)
- X {
- X bnode = (Node *) ldata(ptr);
- X if (on_node(bnode, nf_NONVOL))
- X save_novol(bnode);
- X }
- X
- X /* execute actions */
- X code = carry_out(node, force_exec);
- X if (code.w_status != 0)
- X {
- X oksofar = FALSE;
- X sprintf(scratchbuf, "error in actions for %s", node->n_name);
- X for_list (ptr, node->n_new)
- X {
- X bnode = (Node *) ldata(ptr);
- X add_error(bnode, new_name(scratchbuf), LNULL, TRUE);
- X }
- X
- X if (! xflag)
- X {
- X if (code.w_termsig == 0)
- X printf("*** Error code %d\n", code.w_retcode);
- X else
- X printf("*** Termination code %d\n", code.w_termsig);
- X }
- X
- X cake_error(node);
- X goto endit;
- X }
- X
- X /* clean up after actions */
- X for_list (ptr, node->n_new)
- X {
- X bnode = (Node *) ldata(ptr);
- X if (on_node(bnode, nf_NONVOL) && ! diff_novol(bnode))
- X node_resetstat(bnode);
- X or (rflag)
- X node_setstat(bnode);
- X else
- X node_stat(bnode);
- X }
- X }
- X
- Xendit:
- X
- X cdebug("update finished\n");
- X for_list (ptr, node->n_new)
- X {
- X bnode = (Node *) ldata(ptr);
- X if (oksofar)
- X {
- X if (on_node(bnode, nf_EXIST) || on_node(bnode, nf_PSEUDO) || nflag)
- X bnode->n_kind = n_OK;
- X else
- X {
- X set_node(bnode, nf_ERR);
- X if (length(node->n_act) == 0)
- X sprintf(scratchbuf, "no actions to make %s with", bnode->n_name);
- X else
- X sprintf(scratchbuf, "action did not create %s", bnode->n_name);
- X
- X add_error(bnode, new_name(scratchbuf), LNULL, TRUE);
- X trace_errs(bnode);
- X }
- X }
- X
- X#ifdef CAKEDEBUG
- X if (cakedebug)
- X print_node(bnode);
- X#endif
- X }
- X
- X put_trail("update", "finish");
- X}
- X
- X/*
- X** Execute the plan prepared by chase.c
- X** Prevent the deletion of the primary targets by cleanup.
- X*/
- X
- Xexecute(root)
- Xreg Node *root;
- X{
- X reg List *ptr;
- X reg Node *target;
- X
- X for_list (ptr, root->n_old)
- X {
- X target = (Node *) ldata(ptr);
- X set_node(target, nf_NODELETE);
- X }
- X
- X update(root, 0, FALSE);
- X}
- X
- X/*
- X** Carry out the specified actions and return the exit code.
- X** Note that an empty list of actions is perfectly acceptable.
- X*/
- X
- X#define START_SCRIPT "{"
- X#define FINISH_SCRIPT "}"
- X
- XWait
- Xcarry_out(node, force_exec)
- Xreg Node *node;
- Xreg bool force_exec;
- X{
- X extern char *expand_cmds();
- X extern Wait action();
- X reg List *ptr;
- X reg Act *act;
- X reg Node *bnode;
- X Wait code;
- X
- X if (Gflag && ! nflag)
- X {
- X for_list (ptr, node->n_new)
- X {
- X bnode = (Node *) ldata(ptr);
- X if (on_node(bnode, nf_EXIST))
- X {
- X cdebug("removing %s for -G\n", bnode->n_name);
- X cake_remove(bnode->n_name);
- X }
- X }
- X }
- X
- X for_list (ptr, node->n_act)
- X {
- X act = (Act *) ldata(ptr);
- X
- X if (nflag)
- X {
- X if (off_act(act, af_MINUSN) && ! force_exec)
- X show_act(act->a_str, (char *) NULL);
- X else
- X {
- X reset_act(act, af_SILENT);
- X printf("executing ...\n");
- X code = action(act, node);
- X printf("... done\n");
- X if (code.w_status != 0)
- X return code;
- X }
- X
- X continue;
- X }
- X
- X code = action(act, node);
- X if (code.w_status != 0)
- X return code;
- X }
- X
- X code.w_status = 0;
- X return code;
- X}
- X
- X/*
- X** Execute the given command and return its status,
- X** modified by flags and prefixes.
- X*/
- X
- XWait
- Xaction(act, node)
- Xreg Act *act;
- Xreg Node *node;
- X{
- X extern int cake_proc();
- X extern Wait cake_wait();
- X Wait code;
- X reg A_kind type;
- X reg int pid;
- X reg char *after;
- X
- X put_trail("action", "start");
- X after = expand_cmds(act->a_str);
- X if (! (on_act(act, af_SILENT) || sflag))
- X show_act(act->a_str, after);
- X act->a_str = after;
- X
- X if (on_act(act, af_SCRIPT))
- X type = Script;
- X or (on_act(act, af_SYSTEM))
- X type = System;
- X else
- X type = Exec;
- X
- X pid = cake_proc(act->a_str, type, (char *) NULL, node, (int (*)()) NULL, (List *) NULL);
- X code = cake_wait(pid);
- X
- X if (on_act(act, af_IGNORE) || iflag)
- X code.w_status = 0;
- X
- X if (code.w_status != 0 && ! kflag)
- X exit_cake(FALSE);
- X
- X put_trail("action", "finish");
- X return code;
- X}
- X
- X/*
- X** Print an action in the format specified by the options.
- X** The two args are the action before and after expansion.
- X** The second may be NULL, in which case show_act does the
- X** expansion itself.
- X*/
- X
- Xshow_act(before, after)
- Xreg char *before;
- Xreg char *after;
- X{
- X extern char *squeeze();
- X reg char *form;
- X
- X if (bflag)
- X form = before;
- X or (after != NULL)
- X form = after;
- X else
- X form = expand_cmds(before);
- X
- X if (wflag)
- X printf("%s", form);
- X else
- X printf("%s", squeeze(form));
- X}
- X
- X/*
- X** Reduce the width of the given command string
- X** by squeezing out extra spaces and tabs.
- X*/
- X
- Xchar *
- Xsqueeze(cmd)
- Xreg char *cmd;
- X{
- X char buf[MAXSIZE];
- X reg char *s;
- X reg int i, oldi;
- X reg bool inquotes;
- X reg bool insingle;
- X reg bool indouble;
- X reg bool lastblank;
- X
- X s = cmd;
- X i = 0;
- X lastblank = FALSE;
- X while (*s != '\0')
- X {
- X while (*s != '\0' && (*s == ' ' || *s == '\t'))
- X s++;
- X
- X if (lastblank && (*s == '\n' || *s == '\r' || *s == '\f'))
- X i--;
- X
- X oldi = i;
- X inquotes = FALSE;
- X for (; *s != '\0' && ((*s != ' ' && *s != '\t') || inquotes); s++)
- X {
- X if (*s == '\\')
- X {
- X buf[i++] = *s;
- X if (s[1] != '\0')
- X buf[i++] = *++s;
- X }
- X else
- X {
- X if (*s == '"' && ! (inquotes && insingle))
- X {
- X inquotes = ! inquotes;
- X indouble = TRUE;
- X insingle = FALSE;
- X }
- X or (*s == '\'' && ! (inquotes && indouble))
- X {
- X inquotes = ! inquotes;
- X insingle = TRUE;
- X indouble = FALSE;
- X }
- X
- X buf[i++] = *s;
- X }
- X }
- X
- X if (i == oldi || buf[i-1] == '\n' || buf[i-1] == '\r' || buf[i-1] == '\f')
- X lastblank = FALSE;
- X else
- X {
- X lastblank = TRUE;
- X buf[i++] = ' ';
- X }
- X }
- X
- X buf[i] = '\0';
- X if (i >= MAXSIZE)
- X {
- X fprintf(stderr, "cake internal error: command '%s' too long\n", buf);
- X exit_cake(FALSE);
- X }
- X
- X while (buf[i-1] == ' ' || buf[i-1] == '\t')
- X buf[--i] = '\0';
- X
- X return new_name(buf);
- X}
- X
- X/*
- X** Clean up after an error or interrupt.
- X*/
- X
- Xcake_error(node)
- Xreg Node *node;
- X{
- X reg List *ptr, *ptr1;
- X reg Node *bnode, *onode;
- X
- X for_list (ptr, node->n_new)
- X {
- X bnode = (Node *) ldata(ptr);
- X for_list (ptr1, bnode->n_old)
- X {
- X onode = (Node *) ldata(ptr1);
- X set_node(onode, nf_NODELETE);
- X }
- X
- X if (on_node(bnode, nf_EXIST) && off_node(bnode, nf_PRECIOUS))
- X cake_remove(bnode->n_name);
- X }
- X}
- X
- X/*
- X** Clean up after all the fuss.
- X*/
- X
- Xcleanup()
- X{
- X extern List *get_allnodes();
- X reg List *ptr, *ptr1;
- X reg List *nodes;
- X reg Node *node, *onode;
- X
- X cdebug("cleanup:\n");
- X
- X if (nflag)
- X return;
- X
- X nodes = get_allnodes();
- X for_list (ptr, nodes)
- X {
- X node = (Node *) ldata(ptr);
- X cdebug("considering %s: ", node->n_name);
- X
- X if (off_node(node, nf_EXIST))
- X {
- X cdebug("nonexistent\n");
- X continue;
- X }
- X
- X if (on_node(node, nf_ERR) || is_noway(node))
- X {
- X cdebug("errors or noway\n");
- X continue;
- X }
- X
- X if (! dflag && off_node(node, nf_REDUNDANT))
- X {
- X cdebug("no flag\n");
- X continue;
- X }
- X
- X /* file exists and OK, shall we delete it ? */
- X
- X /* not if we thought earlier it need it */
- X if (on_node(node, nf_NODELETE))
- X {
- X cdebug("nodelete flag\n");
- X continue;
- X }
- X
- X /* not if it cannot be regenerated at all */
- X if (length(node->n_act) == 0)
- X {
- X cdebug("nonregenerable\n");
- X continue;
- X }
- X
- X /* not if it cannot be regenerated as is */
- X if ((node->n_utime < node->n_rtime) && off_node(node, nf_NEWFILE))
- X {
- X cdebug("nonregenerable as is\n");
- X continue;
- X }
- X
- X /* or if its ancestors are not all OK */
- X for_list (ptr1, node->n_old)
- X {
- X onode = (Node *) ldata(ptr1);
- X if (! is_ok(onode))
- X {
- X cdebug("ancestor not ok\n");
- X goto nextnode;
- X }
- X }
- X
- X cdebug("DELETED\n");
- X cake_remove(node->n_name);
- X
- X nextnode: ;
- X }
- X}
- SHAR_EOF
- if test 12578 -ne "`wc -c < 'act.c'`"
- then
- echo shar: "error transmitting 'act.c'" '(should have been 12578 characters)'
- fi
- fi
- echo shar: "extracting 'chase.c'" '(13609 characters)'
- if test -f 'chase.c'
- then
- echo shar: "will not over-write existing file 'chase.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'chase.c'
- X/*
- X** Module to chase Cake dependencies.
- X*/
- X
- Xstatic char
- Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/chase.c,v 1.14 86/07/19 12:22:39 zs Exp $";
- X
- X#include "cake.h"
- X
- X/*
- X** The main chasing function. It checks all entries to see
- X** if they describe a dependency of the name. If the second arg
- X** is not NULL, it is taken as a fixed choice (by another do_chase)
- X** as to which entry will actually be used to generate the name.
- X**
- X** The kinds of nodes returned by do_chase are as follows.
- X** OK means that no action is needed to update the name.
- X** CANDO means that the action is known and there is no reason
- X** why it shouldn't succeed. NOWAY is set when neither of those
- X** conditions is satisfied. nf_ERR means that some error has
- X** occurred; nf_ERR nodes are never touched again; except for
- X** printing the error messages themselves. (NOWAY nodes *are*
- X** touched by act.c to update as many ancestors as possible.)
- X**
- X** Whenever nf_ERR is not set, do_chase sets the utime field,
- X** and the rtime field as well if the file exists.
- X*/
- X
- Xdo_chase(node, picked)
- Xreg Node *node;
- Xreg Entry *picked;
- X{
- X extern get_utime();
- X extern time_t cake_gettime();
- X extern Node *chase();
- X extern Node *chase_node();
- X extern time_t pick_time();
- X extern bool match();
- X extern bool eval();
- X extern Entry *ground_entry();
- X extern Test *deref_test();
- X extern deref_entry();
- X extern List *entries;
- X extern char *list_names();
- X Env env;
- X reg List *ptr, *ptr1, *ptr2;
- X reg Node *newnode, *onode;
- X reg Entry *entry, *newentry;
- X reg Pat *pat;
- X reg List *entry_anay, *entry_ayea; /* of Entry */
- X reg List *miss_anay, *miss_ayea; /* of Node */
- X reg List *pot_entry; /* of Entry */
- X reg List *pot_pat; /* of Pat */
- X reg List *probe_old; /* of Node */
- X reg bool found, missing;
- X reg bool singleton, orphan;
- X
- X put_trail("do_chase", "start");
- X cdebug("chasing %s\n", node->n_name);
- X
- X if (off_node(node, nf_EXIST))
- X set_node(node, nf_NEWFILE);
- X
- X /* find all entries which could generate this name */
- X pot_entry = makelist0();
- X pot_pat = makelist0();
- X for_list (ptr, entries)
- X {
- X entry = (Entry *) ldata(ptr);
- X /* try everything on the left side of the entry */
- X for_list (ptr1, entry->e_new)
- X {
- X pat = (Pat *) ldata(ptr1);
- X if (match(env, node->n_name, pat))
- X {
- X if ((newentry = ground_entry(env, entry)) == (Entry *) NULL)
- X {
- X sprintf(scratchbuf, "cannot perform substitutions on entry for %s",
- X node->n_name);
- X add_error(node, new_name(scratchbuf), LNULL, TRUE);
- X goto end;
- X }
- X
- X#ifdef CAKEDEBUG
- X if (entrydebug)
- X {
- X printf("Applicable entry\n");
- X print_entry(newentry);
- X }
- X#endif
- X
- X addtail(pot_entry, newentry); /* na */
- X addtail(pot_pat, pat); /* na */
- X break;
- X }
- X }
- X }
- X
- X cdebug("%s: %d potentials\n", node->n_name, length(pot_entry));
- X
- X /* find out which tests are satisfied */
- X entry_anay = makelist0();
- X entry_ayea = makelist0();
- X for_2list (ptr1, ptr2, pot_entry, pot_pat)
- X {
- X entry = (Entry *) ldata(ptr1);
- X pat = (Pat *) ldata(ptr2);
- X
- X for_list (ptr, entry->e_when)
- X {
- X reg Node *whennode;
- X reg Pat *whenpat;
- X
- X whenpat = (Pat *) ldata(ptr);
- X whennode = chase(whenpat->p_str, whenpat->p_flag, (Entry *) NULL);
- X if (off_node(whennode, nf_ERR))
- X {
- X if (is_ok(whennode))
- X continue;
- X
- X if (nflag && off_node(whennode, nf_WARNED))
- X {
- X printf("cake -n: warning, need to make %s to find dependencies\n",
- X whenpat->p_str);
- X set_node(whennode, nf_WARNED);
- X }
- X
- X update(whennode, 100, TRUE);
- X }
- X
- X if (on_node(whennode, nf_ERR) || ! is_ok(whennode))
- X {
- X sprintf(scratchbuf, "cannot find out if entry applies to %s",
- X node->n_name);
- X add_error(node, new_name(scratchbuf), makelist(whennode), TRUE);
- X return;
- X }
- X }
- X
- X#ifdef CAKEDEBUG
- X if (entrydebug)
- X {
- X printf("about to test condition\n");
- X print_entry(entry);
- X }
- X#endif
- X
- X entry->e_cond = deref_test(entry->e_cond);
- X if (! eval(node, entry->e_cond, env))
- X {
- X cdebug("condition FALSE\n");
- X continue;
- X }
- X
- X /* here we know that this entry applies */
- X deref_entry(env, entry);
- X
- X if (Lflag)
- X {
- X for_list (ptr, entry->e_old)
- X {
- X reg Pat *opat;
- X
- X opat = (Pat *) ldata(ptr);
- X if (streq(node->n_name, opat->p_str))
- X {
- X cdebug("found loop in entry at %s\n", node->n_name);
- X continue;
- X }
- X }
- X }
- X
- X node->n_flag |= pat->p_flag;
- X if (length(entry->e_act) == 0)
- X addtail(entry_anay, entry); /* no assigment */
- X else
- X addtail(entry_ayea, entry); /* no assigment */
- X }
- X
- X if (on_node(node, nf_ERR))
- X return;
- X
- X cdebug("%s: no action: %d, with actions: %d\n",
- X node->n_name, length(entry_anay), length(entry_ayea));
- X
- X /* All entries considered from now on are ground */
- X
- X /* see if the file is an original */
- X if (length(entry_anay) == 0 && length(entry_ayea) == 0)
- X {
- X if (off_node(node, nf_EXIST))
- X {
- X cdebug("%s: noway\n", node->n_name);
- X node->n_kind = n_NOWAY;
- X node->n_utime = GENESIS;
- X sprintf(scratchbuf, "base file %s does not exist", node->n_name);
- X add_error(node, new_name(scratchbuf), LNULL, FALSE);
- X goto end;
- X }
- X
- X set_node(node, nf_ORIG);
- X cdebug("%s: orig ok\n", node->n_name);
- X node->n_kind = n_OK;
- X node->n_utime = node->n_rtime;
- X goto end;
- X }
- X
- X /* see to actionless dependencies */
- X missing = FALSE;
- X miss_anay = NULL;
- X for_list (ptr, entry_anay)
- X {
- X entry = (Entry *) ldata(ptr);
- X for_list (ptr1, entry->e_old)
- X {
- X pat = (Pat *) ldata(ptr1);
- X newnode = chase(pat->p_str, pat->p_flag, (Entry *) NULL);
- X if (on_node(newnode, nf_ERR) || is_noway(newnode))
- X {
- X missing = TRUE;
- X miss_anay = addtail(miss_anay, newnode);
- X }
- X
- X addtail(node->n_old, newnode); /* na */
- X }
- X }
- X
- X cdebug("%s: unconditional dependencies, %s\n",
- X node->n_name, missing? "some missing": "all there");
- X
- X /*
- X ** If necessary, choose a feasible action dependency.
- X ** However, if there is only one, select it even if
- X ** it is not feasible.
- X */
- X
- X found = FALSE;
- X miss_ayea = NULL;
- X if (picked == (Entry *) NULL)
- X {
- X singleton = (length(entry_ayea) == 1);
- X orphan = (length(entry_ayea) == 0);
- X
- X for_list (ptr, entry_ayea)
- X {
- X entry = (Entry *) ldata(ptr);
- X /* first copy of this code, with chase */
- X found = TRUE; /* assume it for the moment */
- X probe_old = makelist0();
- X for_list (ptr1, entry->e_old)
- X {
- X pat = (Pat *) ldata(ptr1);
- X newnode = chase(pat->p_str, pat->p_flag, (Entry *) NULL);
- X if (on_node(newnode, nf_ERR) || is_noway(newnode))
- X {
- X found = FALSE;
- X miss_ayea = addtail(miss_ayea, newnode);
- X if (! singleton)
- X break;
- X }
- X
- X addtail(probe_old, newnode); /* na */
- X }
- X
- X if (found)
- X break;
- X }
- X }
- X else
- X {
- X singleton = TRUE;
- X orphan = FALSE;
- X
- X cdebug("%s: was given generator\n", node->n_name);
- X entry = picked;
- X
- X /* second copy of this code, with chase_node */
- X found = TRUE; /* assume it for the moment */
- X probe_old = makelist0();
- X for_list (ptr1, entry->e_old)
- X {
- X pat = (Pat *) ldata(ptr1);
- X newnode = chase_node(pat->p_str);
- X if (on_node(newnode, nf_ERR) || is_noway(newnode))
- X {
- X found = FALSE;
- X miss_ayea = addtail(miss_ayea, newnode);
- X if (! singleton)
- X break;
- X }
- X
- X addtail(probe_old, newnode); /* na */
- X }
- X }
- X
- X if (found)
- X {
- X /* we have found an applicable entry */
- X cdebug("%s: found feasible generator\n", node->n_name);
- X addlist(node->n_old, probe_old); /* na */
- X node->n_act = entry->e_act;
- X if (picked == (Entry *) NULL)
- X set_buddies(node, entry);
- X picked = entry;
- X }
- X or (singleton)
- X {
- X /* we have only one (inapplicable) entry */
- X /* so we shall make do as best we can */
- X cdebug("%s: found single infeasible generator\n", node->n_name);
- X addlist(node->n_old, probe_old); /* na */
- X node->n_act = entry->e_act;
- X if (picked == (Entry *) NULL)
- X set_buddies(node, entry);
- X picked = entry;
- X }
- X or (orphan && on_node(node, nf_PSEUDO))
- X {
- X /* no entry is needed, act as we had one */
- X found = TRUE;
- X cdebug("%s: no generator, no problem\n", node->n_name);
- X node->n_act = makelist0();
- X }
- X else
- X {
- X cdebug("%s: no feasible generator\n", node->n_name);
- X node->n_act = makelist0();
- X }
- X
- X if (length(node->n_act) > 0 && length(picked->e_old) == 0)
- X node->n_utime = cake_gettime();
- X else
- X get_utime(node, TRUE);
- X
- X for_list (ptr, node->n_old)
- X {
- X newnode = (Node *) ldata(ptr);
- X if (on_node(newnode, nf_NONVOL))
- X set_node(node, nf_DEPNONVOL);
- X }
- X
- X if (missing)
- X {
- X node->n_kind = n_NOWAY;
- X sprintf(scratchbuf, "%s is missing the prerequisite%s %s",
- X node->n_name, length(miss_anay)==1? "": "s", list_names(miss_anay));
- X add_error(node, new_name(scratchbuf), miss_anay, FALSE);
- X }
- X or (! found)
- X {
- X node->n_kind = n_NOWAY;
- X if (miss_ayea == (List *) NULL)
- X sprintf(scratchbuf, "%s has no applicable entries with actions\n",
- X node->n_name);
- X else
- X sprintf(scratchbuf, "%s is missing the ancestor%s %s",
- X node->n_name, length(miss_ayea)==1? "": "s", list_names(miss_ayea));
- X
- X add_error(node, new_name(scratchbuf), miss_ayea, FALSE);
- X }
- X or (on_node(node, nf_EXIST) && node->n_utime <= node->n_rtime)
- X node->n_kind = n_OK;
- X or (on_node(node, nf_PSEUDO) && length(node->n_act) == 0)
- X {
- X node->n_kind = n_OK;
- X for_list (ptr, node->n_old)
- X {
- X onode = (Node *) ldata(ptr);
- X if (is_cando(onode))
- X node->n_kind = n_CANDO;
- X }
- X }
- X else
- X node->n_kind = n_CANDO;
- X
- Xend:
- X#ifdef CAKEDEBUG
- X if (cakedebug)
- X {
- X printf("chase exit\n");
- X print_node(node);
- X }
- X#endif
- X
- X put_trail("do_chase", "finish");
- X}
- X
- X/*
- X** Calculate the "update time" of the given node. The second arg
- X** tells us whether we should set a flag for nonvolatile ancestors.
- X*/
- X
- Xget_utime(node, planning)
- Xreg Node *node;
- Xreg bool planning;
- X{
- X extern time_t get_youngest(), cake_gettime();
- X reg time_t youngest;
- X
- X if ((youngest = get_youngest(node, planning)) == GENESIS)
- X node->n_utime = cake_gettime();
- X else
- X node->n_utime = youngest;
- X}
- X
- X/*
- X** Return the time of update of the youngest dependent.
- X*/
- X
- Xtime_t
- Xget_youngest(node, planning)
- Xreg Node *node;
- Xreg bool planning;
- X{
- X reg List *ptr;
- X reg Node *onode;
- X reg time_t youngest, picked_time;
- X reg List *errnodes;
- X
- X youngest = GENESIS;
- X errnodes = NULL;
- X for_list (ptr, node->n_old)
- X {
- X onode = (Node *) ldata(ptr);
- X if (on_node(onode, nf_ERR))
- X errnodes = addtail(errnodes, onode);
- X else
- X {
- X if ((picked_time = pick_time(onode, planning)) > youngest)
- X youngest = picked_time;
- X }
- X }
- X
- X if (errnodes != (List *) NULL)
- X {
- X sprintf(scratchbuf, "don't know what to do with %s because of problems with %s",
- X node->n_name, list_names(errnodes));
- X add_error(node, new_name(scratchbuf), errnodes, TRUE);
- X }
- X
- X return youngest;
- X}
- X
- X/*
- X** Take care of the names mentioned alongside node's
- X** on the left hand side of the given ground entry.
- X**
- X** If a node exists for one of these names we know that
- X** a producer must have been chosen for it, and we know that
- X** it is not this rule (if it were, then the caller would not
- X** have done anything about buddies). This is an inconsistency.
- X*/
- X
- Xset_buddies(node, entry)
- Xreg Node *node;
- Xreg Entry *entry;
- X{
- X extern Node *chase_node();
- X reg List *list;
- X reg List *ptr;
- X reg Node *newnode;
- X reg Pat *pat;
- X reg List *errnodes;
- X
- X put_trail("set_buddies", "start");
- X list = makelist(node);
- X errnodes = NULL;
- X for_list (ptr, entry->e_new)
- X {
- X pat = (Pat *) ldata(ptr);
- X if (streq(pat->p_str, node->n_name))
- X continue;
- X
- X if ((newnode = chase_node(pat->p_str)) != (Node *) NULL)
- X errnodes = addtail(errnodes, newnode);
- X else
- X {
- X newnode = chase(pat->p_str, pat->p_flag, entry);
- X addtail(list, newnode); /* no assigment */
- X }
- X }
- X
- X for_list (ptr, list)
- X {
- X newnode = (Node *) ldata(ptr);
- X newnode->n_new = list;
- X
- X if (errnodes != (List *) NULL)
- X {
- X sprintf(scratchbuf, "cannot update %s because of interference with %s %s",
- X newnode->n_name, (length(errnodes) == 1)? "buddy": "buddies",
- X list_names(errnodes));
- X add_error(node, new_name(scratchbuf), errnodes, TRUE);
- X }
- X }
- X
- X put_trail("set_buddies", "finish");
- X}
- X
- X/*
- X** Pick the appropriate time to use in decisions
- X** about dependencies. The algorithms differ in the
- X** twp phases: in the execution phase real times
- X** override any calculated times.
- X*/
- X
- Xtime_t
- Xpick_time(node, planning)
- Xreg Node *node;
- Xreg bool planning;
- X{
- X if (off_node(node, nf_EXIST))
- X return node->n_utime;
- X
- X if (planning)
- X return max(node->n_rtime, node->n_utime);
- X
- X return node->n_rtime;
- X}
- X
- X/*
- X** Chase down the ancestors of the given name.
- X** Return the node describing the dependency graph.
- X**
- X** Note that this is merely an interface function,
- X** serving to cache previous results and to detect cycles.
- X*/
- X
- Xchar *goal_stack[MAXGSTACK];
- Xint goal_stackp = 0;
- X
- XNode *
- Xchase(name, flag, picked)
- Xreg char *name;
- Xreg bool flag;
- Xreg Entry *picked;
- X{
- X extern Table node_tab;
- X extern do_chase();
- X extern char *find_circle();
- X reg Node *node;
- X
- X if ((node = (Node *) lookup_table(node_tab, name)) == NULL)
- X {
- X node = make_node(name);
- X if (goal_stackp >= MAXGSTACK)
- X {
- X printf("cake: dependency nesting level %d too deep\n", goal_stackp);
- X exit_cake(FALSE);
- X }
- X
- X goal_stack[goal_stackp++] = name;
- X#ifdef CAKEDEBUG
- X cdebug("stack[%d] = %s\n", goal_stackp-1, goal_stack[goal_stackp-1]);
- X#endif
- X set_node(node, nf_BUSY);
- X insert_table(node_tab, node);
- X do_chase(node, picked);
- X --goal_stackp;
- X reset_node(node, nf_BUSY);
- X }
- X else
- X {
- X cdebug("Using cache for %s\n", name);
- X if (on_node(node, nf_BUSY))
- X {
- X node->n_flag |= flag;
- X sprintf(scratchbuf, "%s depends upon itself %s", node->n_name,
- X find_circle(node->n_name));
- X add_error(node, new_name(scratchbuf), LNULL, TRUE);
- X put_trail("chase", "finish");
- X return node;
- X }
- X }
- X
- X node->n_flag |= flag;
- X put_trail("chase", "finish");
- X return node;
- X}
- SHAR_EOF
- if test 13609 -ne "`wc -c < 'chase.c'`"
- then
- echo shar: "error transmitting 'chase.c'" '(should have been 13609 characters)'
- fi
- fi
- echo shar: "extracting 'entry.c'" '(11376 characters)'
- if test -f 'entry.c'
- then
- echo shar: "will not over-write existing file 'entry.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'entry.c'
- X/*
- X** Module to record and process Cake dependency entries.
- X*/
- X
- Xstatic char
- Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/entry.c,v 1.14 86/07/19 12:22:52 zs Exp $";
- X
- X#include "cake.h"
- X#include <ctype.h>
- X
- XList *entries;
- XEntry *main_entry;
- X
- Xextern Test *ground_test();
- X
- X#define ground_pat(env, pat) make_pat(ground(env, pat->p_str), pat->p_cmd, pat->p_flag);
- X#define ground_act(env, act) make_act(ground(env, act->a_str), act->a_flag);
- X
- X/*
- X** Initialise ALL data structures about entries.
- X*/
- X
- Xinit_entry()
- X{
- X entries = makelist0();
- X main_entry = (Entry *) NULL;
- X}
- X
- X/*
- X** Deposit an entry just read in.
- X*/
- X
- Xnew_entry(deps, acts)
- Xreg List *deps; /* of Entry */
- Xreg List *acts; /* of Pat */
- X{
- X reg List *ptr;
- X reg Entry *entry;
- X
- X for_list (ptr, deps)
- X {
- X entry = (Entry *) ldata(ptr);
- X entry->e_act = acts;
- X addtail(entries, entry); /* no assignment */
- X }
- X}
- X
- X/*
- X** Prepare entries for matches against their left hand sides.
- X** This essentially means dereferencing any command patterns.
- X** Another minor correction is also done here: if -n is given
- X** then we set nf_PRECIOUS so no file is deleted.
- X*/
- X
- Xprep_entries()
- X{
- X extern List *break_pat();
- X reg List *ptr, *ptr1;
- X reg Entry *entry;
- X reg Pat *pat;
- X reg List *newnew;
- X
- X for_list (ptr, entries)
- X {
- X entry = (Entry *) ldata(ptr);
- X
- X newnew = makelist0();
- X for_list (ptr1, entry->e_new)
- X {
- X pat = (Pat *) ldata(ptr1);
- X if (on_pat(pat, nf_WHEN))
- X {
- X printf("cake: inappropriate flag '*' after target %s ignored\n",
- X pat->p_str);
- X reset_pat(pat, nf_WHEN);
- X }
- X
- X if (nflag)
- X set_pat(pat, nf_PRECIOUS);
- X
- X if (! pat->p_cmd)
- X addtail(newnew, pat); /* na */
- X else
- X {
- X deref(pat, TRUE);
- X addlist(newnew, break_pat(pat));/* na */
- X }
- X }
- X
- X entry->e_new = newnew;
- X
- X for_list (ptr1, entry->e_old)
- X {
- X pat = (Pat *) ldata(ptr1);
- X if (pat->p_cmd && on_pat(pat, nf_WHEN))
- X {
- X printf("cake: inappropriate flag '*' after command source %s ignored\n",
- X pat->p_str);
- X reset_pat(pat, nf_WHEN);
- X }
- X }
- X
- X#ifdef CAKEDEBUG
- X if (entrydebug)
- X {
- X printf("prepared entry:\n");
- X print_entry(entry);
- X }
- X#endif
- X }
- X}
- X
- X/*
- X** Enter the last (main) entry. This entry has a distinguished
- X** left hand side consisting of the sole pattern CHASEROOT.
- X** This is the pattern which cake tries to make up-to-date.
- X** If there were nonoption arguments on the command line,
- X** CHASEROOT is made to depend on them; otherwise the left hand
- X** side of the first concrete entry is used, as in make.
- X** However, if the first concrete entry is in an included file,
- X** we keep looking, unless it had a double colon.
- X*/
- X
- Xfinal_entry(argc, argv)
- Xreg int argc;
- Xreg char *argv[];
- X{
- X extern bool hasvars();
- X reg List *ptr, *ptr1;
- X reg Entry *entry, *foundentry;
- X reg Pat *pat;
- X reg bool found_main, found_incl;
- X reg int i;
- X
- X main_entry = make(Entry);
- X main_entry->e_new = makelist(make_pat(CHASEROOT, FALSE, nf_PSEUDO|nf_NODELETE));
- X main_entry->e_old = makelist0();
- X main_entry->e_cond = (Test *) NULL;
- X main_entry->e_act = makelist0();
- X
- X cdebug("target count %d\n", argc-1);
- X
- X if (argc > 1)
- X {
- X for (i = 1; i < argc; i++)
- X {
- X cdebug("target %s\n", argv[i]);
- X addtail(main_entry->e_old, make_pat(argv[i], FALSE, 0)); /* na */
- X }
- X }
- X else
- X {
- X /* find the first entry without variables */
- X found_main = FALSE;
- X found_incl = FALSE;
- X for_list (ptr, entries)
- X {
- X entry = (Entry *) ldata(ptr);
- X for_list (ptr1, entry->e_new)
- X {
- X pat = (Pat *) ldata(ptr1);
- X if (hasvars(pat->p_str))
- X goto nextentry;
- X }
- X
- X if (streq(entry->e_file, cakefile) || entry->e_dblc)
- X {
- X found_main = TRUE;
- X foundentry = entry;
- X break;
- X }
- X or (! found_incl)
- X {
- X found_incl = TRUE;
- X foundentry = entry;
- X }
- X
- X nextentry: ;
- X }
- X
- X if (! found_main && ! found_incl)
- X {
- X printf("cake: no entries without variables\n");
- X printf("cake: don't know what cake to bake\n");
- X exit(1);
- X }
- X
- X /* update everything on its left side */
- X for_list (ptr, foundentry->e_new)
- X {
- X pat = (Pat *) ldata(ptr);
- X addtail(main_entry->e_old, pat); /* na */
- X }
- X }
- X
- X addtail(entries, main_entry); /* no assigment */
- X}
- X
- X
- X/*
- X** Return a new entry which is a ground version of the one passed.
- X** Process '*' flags and set up e_when accordingly.
- X*/
- X
- XEntry *
- Xground_entry(env, entry)
- XEnv env;
- Xreg Entry *entry;
- X{
- X extern do_when();
- X extern List *break_pat();
- X extern char *ground();
- X reg List *ptr;
- X reg Entry *newentry;
- X reg Pat *pat, *newpat;
- X reg Act *act, *newact;
- X
- X put_trail("ground_entry", "start");
- X newentry = make(Entry);
- X newentry->e_new = makelist0();
- X newentry->e_old = makelist0();
- X newentry->e_act = makelist0();
- X newentry->e_when = makelist0();
- X
- X for_list (ptr, entry->e_new)
- X {
- X /* prep_entries made these patterns command free */
- X pat = (Pat *) ldata(ptr);
- X newpat = ground_pat(env, pat);
- X do_when(newentry, newpat);
- X addtail(newentry->e_new, newpat); /* na */
- X }
- X
- X for_list (ptr, entry->e_old)
- X {
- X pat = (Pat *) ldata(ptr);
- X newpat = ground_pat(env, pat);
- X do_when(newentry, newpat);
- X addtail(newentry->e_old, newpat); /* na */
- X }
- X
- X for_list (ptr, entry->e_act)
- X {
- X act = (Act *) ldata(ptr);
- X newact = ground_act(env, act);
- X addtail(newentry->e_act, newact); /* na */
- X }
- X
- X newentry->e_cond = ground_test(env, entry->e_cond);
- X
- X put_trail("ground_entry", "finish");
- X return newentry;
- X}
- X
- X/*
- X** Look after '*' (when) flags.
- X*/
- X
- Xdo_when(entry, pat)
- Xreg Entry *entry;
- Xreg Pat *pat;
- X{
- X if (on_pat(pat, nf_WHEN))
- X {
- X reset_pat(pat, nf_WHEN);
- X entry->e_when = addtail(entry->e_when, pat);
- X }
- X}
- X
- X/*
- X** Ground a test.
- X*/
- X
- XTest *
- Xground_test(env, test)
- XEnv env;
- Xreg Test *test;
- X{
- X extern char *ground();
- X reg List *ptr;
- X reg Pat *pat, *newpat;
- X reg Test *newtest;
- X
- X if (test == (Test *) NULL)
- X return test;
- X
- X put_trail("ground_test", "start");
- X switch (test->t_kind)
- X {
- X
- Xwhen t_TRUE:
- Xcase t_FALSE: put_trail("ground_test", "finish");
- X return test;
- X
- Xwhen t_AND:
- Xcase t_OR: put_trail("ground_test", "finish");
- X return make_test_b(test->t_kind,
- X ground_test(env, test->t_left), ground_test(env, test->t_right));
- X
- Xwhen t_NOT: put_trail("ground_test", "finish");
- X return make_test_u(test->t_kind, ground_test(env, test->t_left));
- X
- Xwhen t_CMD: put_trail("ground_test", "finish");
- X return make_test_c(ground(env, test->t_cmd));
- X
- Xwhen t_MATCH: pat = ground_pat(env, test->t_pat);
- X newtest = make_test_mm(pat);
- X for_list (ptr, test->t_list)
- X {
- X pat = (Pat *) ldata(ptr);
- X newpat = ground_pat(env, pat);
- X addtail(newtest->t_list, newpat); /* na */
- X }
- X
- X put_trail("ground_test", "finish");
- X return newtest;
- X
- Xwhen t_LIST: pat = ground_pat(env, test->t_pat);
- X newtest = make_test_l(pat, makelist0());
- X for_list (ptr, test->t_list)
- X {
- X pat = (Pat *) ldata(ptr);
- X newpat = ground_pat(env, pat);
- X addtail(newtest->t_list, newpat); /* na */
- X }
- X
- X put_trail("ground_test", "finish");
- X return newtest;
- X
- Xwhen t_EXIST: newpat = ground_pat(env, test->t_pat);
- X put_trail("ground_test", "finish");
- X return make_test_s(t_EXIST, newpat);
- X
- Xwhen t_CANDO: newpat = ground_pat(env, test->t_pat);
- X put_trail("ground_test", "finish");
- X return make_test_s(t_CANDO, newpat);
- X
- Xwhen t_OK: newpat = ground_pat(env, test->t_pat);
- X put_trail("ground_test", "finish");
- X return make_test_s(t_OK, newpat);
- X
- Xotherwise: printf("cake internal error: bad test type %x in ground_test\n", test->t_kind);
- X put_trail("ground_test", "finish");
- X return (Test *) NULL;
- X }
- X
- X put_trail("ground_test", "finish");
- X return (Test *) NULL;
- X}
- X
- X/*
- X** Dereference all command patterns in the given entry.
- X*/
- X
- Xderef_entry(env, entry)
- XEnv env;
- Xreg Entry *entry;
- X{
- X reg List *ptr, *ptr1;
- X reg List *newlist;
- X reg List *patlist;
- X reg Pat *pat, *oldpat, *newpat;
- X
- X newlist = makelist0();
- X for_list (ptr, entry->e_old)
- X {
- X pat = (Pat *) ldata(ptr);
- X if (! pat->p_cmd)
- X addtail(newlist, pat); /* na */
- X else
- X {
- X deref(pat, TRUE);
- X patlist = break_pat(pat);
- X for_list (ptr1, patlist)
- X {
- X oldpat = (Pat *) ldata(ptr1);
- X newpat = make_pat(ground(env, oldpat->p_str), FALSE, 0);
- X do_when(entry, newpat);
- X addtail(newlist, newpat); /* na */
- X }
- X }
- X }
- X
- X entry->e_old = newlist;
- X}
- X
- X/*
- X** Dereference a test.
- X*/
- X
- XTest *
- Xderef_test(test)
- Xreg Test *test;
- X{
- X extern char *expand_cmds();
- X reg List *ptr;
- X reg List *newlist;
- X reg Pat *pat;
- X
- X if (test == (Test *) NULL)
- X return test;
- X
- X put_trail("deref_test", "start");
- X switch (test->t_kind)
- X {
- X
- Xwhen t_TRUE:
- Xcase t_FALSE: put_trail("deref_test", "finish");
- X return test;
- X
- Xwhen t_AND:
- Xcase t_OR: test->t_left = deref_test(test->t_left);
- X test->t_right = deref_test(test->t_right);
- X put_trail("deref_test", "finish");
- X return test;
- X
- Xwhen t_NOT: test->t_left = deref_test(test->t_left);
- X put_trail("deref_test", "finish");
- X return test;
- X
- Xwhen t_CMD: test->t_cmd = expand_cmds(test->t_cmd);
- X put_trail("deref_test", "finish");
- X return test;
- X
- Xwhen t_MATCH: deref(test->t_pat, FALSE);
- X for_list (ptr, test->t_list)
- X {
- X pat = (Pat *) ldata(ptr);
- X deref(pat, FALSE);
- X }
- X
- X put_trail("deref_test", "finish");
- X return test;
- X
- Xwhen t_LIST: deref(test->t_pat, FALSE);
- X newlist = makelist0();
- X for_list (ptr, test->t_list)
- X {
- X pat = (Pat *) ldata(ptr);
- X if (! pat->p_cmd)
- X addtail(newlist, pat); /* na */
- X else
- X {
- X deref(pat, TRUE);
- X addlist(newlist, break_pat(pat)); /* na */
- X }
- X }
- X
- X test->t_list = newlist;
- X put_trail("deref_test", "finish");
- X return test;
- X
- Xwhen t_EXIST: deref(test->t_pat, FALSE);
- X put_trail("deref_test", "finish");
- X return test;
- X
- Xwhen t_CANDO: deref(test->t_pat, FALSE);
- X put_trail("deref_test", "finish");
- X return test;
- X
- Xwhen t_OK: deref(test->t_pat, FALSE);
- X put_trail("deref_test", "finish");
- X return test;
- X
- Xotherwise: printf("cake internal error: bad test type %x in deref_test\n", test->t_kind);
- X put_trail("deref_test", "finish");
- X return (Test *) NULL;
- X }
- X
- X put_trail("deref_test", "finish");
- X return (Test *) NULL;
- X}
- X
- XAct *
- Xprep_act(text)
- Xreg char *text;
- X{
- X reg Act *act;
- X reg char *s;
- X
- X act = make(Act);
- X act->a_flag = 0;
- X
- X /* strip trailing space - there is at least the newline */
- X for (s = text+strlen(text)-1; isspace(*s); s--)
- X *s = '\0';
- X
- X /* put just the newline back */
- X strcat(s, "\n");
- X
- X /* strip spaces before flags */
- X for (s = text; isspace(*s); s++)
- X ;
- X
- X /* process the flags */
- X for (; *s != '\0'; s++)
- X if (*s == '@')
- X set_act(act, af_SILENT);
- X or (*s == '!')
- X set_act(act, af_SYSTEM);
- X or (*s == '-')
- X set_act(act, af_IGNORE);
- X or (*s == '+')
- X set_act(act, af_MINUSN);
- X else
- X break;
- X
- X /* strip spaces after flags */
- X for (; isspace(*s); s++)
- X ;
- X
- X act->a_str = new_name(s);
- X return act;
- X}
- X
- XAct *
- Xprep_script(first_act, middle_act, last_act)
- Xreg Act *first_act, *last_act;
- Xreg List *middle_act;
- X{
- X reg List *ptr;
- X reg Act *act;
- X reg char *s;
- X char buf[MAXSCRIPT];
- X
- X buf[0] = '\0';
- X /* handle the first action */
- X for (s = first_act->a_str+1; *s == ' ' || *s == '\t'; s++)
- X ;
- X
- X if (strdiff(s, "\n"))
- X strcat(buf, s);
- X
- X /* handle the middle actions, if any */
- X for_list (ptr, middle_act)
- X {
- X act = (Act *) ldata(ptr);
- X strcat(buf, act->a_str);
- X }
- X
- X /* handle the last action as the first */
- X for (s = last_act->a_str+1; *s == ' ' || *s == '\t'; s++)
- X ;
- X
- X if (strdiff(s, "\n"))
- X strcat(buf, s);
- X
- X /* check for overflow */
- X if (strlen(buf) > MAXSCRIPT)
- X {
- X printf("cake: script too long\n");
- X printf("%s", buf);
- X exit_cake(FALSE);
- X }
- X
- X first_act->a_str = new_name(buf);
- X set_act(first_act, af_SCRIPT);
- X return first_act;
- X}
- SHAR_EOF
- if test 11376 -ne "`wc -c < 'entry.c'`"
- then
- echo shar: "error transmitting 'entry.c'" '(should have been 11376 characters)'
- fi
- fi
- echo shar: "extracting 'error.c'" '(2454 characters)'
- if test -f 'error.c'
- then
- echo shar: "will not over-write existing file 'error.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'error.c'
- X/*
- X** Error handling module.
- X*/
- X
- Xstatic char
- Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/error.c,v 1.15 87/10/05 20:14:20 zs Exp $";
- X
- X#include "cake.h"
- X
- X/*
- X** This function prints out the history of errors
- X** that prevent the proper update of the given node.
- X*/
- X
- Xtrace_errs(node)
- Xreg Node *node;
- X{
- X reg List *ptr;
- X reg Node *bnode;
- X
- X if (on_node(node, nf_TRACED))
- X return;
- X
- X set_node(node, nf_TRACED);
- X for_list (ptr, node->n_badguys)
- X {
- X bnode = (Node *) ldata(ptr);
- X trace_errs(bnode);
- X }
- X
- X if (strdiff(node->n_name, CHASEROOT))
- X printf("%s", node->n_msg);
- X}
- X
- X/*
- X** This function adds msg to the list of error messages
- X** to be printed by trace_errs for the given node.
- X*/
- X
- Xadd_error(node, msg, badguys, iserror)
- Xreg Node *node;
- Xreg char *msg;
- Xreg List *badguys;
- Xreg int iserror;
- X{
- X char buf[MAXSIZE];
- X
- X if (node->n_msg == NULL)
- X node->n_msg = "";
- X
- X if (iserror)
- X set_node(node, nf_ERR);
- X
- X sprintf(buf, "%scake: %s\n", node->n_msg, msg);
- X if (strlen(buf) >= MAXSIZE)
- X {
- X fprintf(stderr, "cake internal error: buffer overflow in add_error\n");
- X exit_cake(FALSE);
- X }
- X
- X node->n_msg = new_name(buf);
- X node->n_badguys = addlist(node->n_badguys, badguys);
- X}
- X
- Xchar *
- Xfind_circle(name)
- Xreg char *name;
- X{
- X extern int goal_stackp;
- X extern char *goal_stack[];
- X char buf[MAXSIZE];
- X reg int i;
- X
- X cdebug("stackp = %d\n", goal_stackp);
- X cdebug("looking for %s\n", goal_stack[goal_stackp-1]);
- X
- X if (goal_stack[goal_stackp-1] == name)
- X return "directly";
- X
- X for (i = 0; i < goal_stackp; i++)
- X {
- X cdebug("checking %d: %s\n", i, goal_stack[i]);
- X if (goal_stack[i] == name)
- X {
- X cdebug("hit\n");
- X strcpy(buf, "through");
- X for (; i < goal_stackp; i++)
- X {
- X strcat(buf, " ");
- X strcat(buf, goal_stack[i]);
- X }
- X
- X if (strlen(buf) >= MAXSIZE)
- X {
- X fprintf(stderr, "cake internal error: buffer overflow in find_circle\n");
- X exit_cake(FALSE);
- X }
- X
- X return new_name(buf);
- X }
- X }
- X
- X fprintf(stderr, "cake internal error: no circularity in find_circle\n");
- X exit_cake(TRUE);
- X return ""; /* to satisfy lint */
- X}
- X
- Xchar *
- Xlist_names(list)
- Xreg List *list; /* of Node */
- X{
- X reg List *ptr;
- X reg Node *node;
- X reg char *sep;
- X char buf[MAXSIZE];
- X
- X buf[0] = '\0';
- X sep = "";
- X for_list (ptr, list)
- X {
- X node = (Node *) ldata(ptr);
- X strcat(buf, sep);
- X strcat(buf, node->n_name);
- X sep = " ";
- X }
- X
- X if (strlen(buf) >= MAXSIZE)
- X {
- X fprintf(stderr, "cake internal error: buffer overflow in list_names\n");
- X exit_cake(FALSE);
- X }
- X
- X return new_name(buf);
- X}
- SHAR_EOF
- if test 2454 -ne "`wc -c < 'error.c'`"
- then
- echo shar: "error transmitting 'error.c'" '(should have been 2454 characters)'
- fi
- fi
- echo shar: "extracting 'expand.c'" '(5774 characters)'
- if test -f 'expand.c'
- then
- echo shar: "will not over-write existing file 'expand.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'expand.c'
- X/*
- X** Module to expand out commands in patterns and actions.
- X*/
- X
- Xstatic char
- Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/expand.c,v 1.14 86/07/19 12:23:01 zs Exp $";
- X
- X#include "cake.h"
- X#include <ctype.h>
- X
- X/*
- X** Expand any commands in actions. Doing this here instead of
- X** in the shell saves time because of cake's command cache.
- X*/
- X
- Xchar *
- Xexpand_cmds(str)
- Xreg char *str;
- X{
- X extern char *get_output();
- X reg char *s;
- X reg int n, cmds, offset;
- X reg int stackp;
- X reg char *rightbr;
- X char *leftbr_stack[MAXNEST];
- X char *nextbr_stack[MAXNEST];
- X char copybuf[MAXSIZE], buf[MAXSIZE];
- X reg char *result;
- X
- X if (index(str, '[') == NULL)
- X return str;
- X
- X put_trail("expand_cmds", "start");
- X cmds = 0;
- X stackp = 0;
- X if (strlen(str) >= MAXSIZE)
- X {
- X fprintf(stderr, "cake internal error: command too long %s\n", str);
- X exit_cake(FALSE);
- X }
- X
- X strcpy(copybuf, str);
- X leftbr_stack[stackp] = copybuf;
- X nextbr_stack[stackp] = NULL;
- X
- X /* Leftbr_stack[stackp] and rightbr enclose commands */
- X /* for stackp > 0; for stackp == 0 they enclose the string */
- X /* Nextbr_stack gives the beginning of the next segment */
- X /* after the corresponding leftbr; == 0 if not known (yet) */
- X /* The top entry on the stack always has nextbr == NULL */
- X
- X for (s = copybuf; s[0] != '\0'; s++)
- X {
- X if (s[0] == '[' && s[1] == '[')
- X {
- X nextbr_stack[stackp] = s;
- X if (++stackp >= MAXNEST)
- X {
- X fprintf(stderr, "cake internal error: command nesting level too deep\n");
- X exit_cake(FALSE);
- X }
- X
- X leftbr_stack[stackp] = s;
- X nextbr_stack[stackp] = NULL;
- X s++; /* avoid problems with [[[cmd]] ... */
- X }
- X or (s[0] == ']' && s[1] == ']')
- X {
- X if (stackp <= 0)
- X continue;
- X
- X cmds++;
- X rightbr = s;
- X
- X leftbr_stack[stackp][0] = '\0';
- X leftbr_stack[stackp][1] = '\0';
- X rightbr[0] = '\0';
- X rightbr[1] = '\0';
- X
- X result = get_output(new_name(leftbr_stack[stackp]+2));
- X cdebug("expansion [[%s]] => [[%s]]\n", leftbr_stack[stackp]+2, result);
- X
- X segcpy(buf, leftbr_stack[stackp-1], nextbr_stack[stackp-1]);
- X strcat(buf, result);
- X offset = strlen(buf) - 1;
- X strcat(buf, rightbr+2);
- X
- X if (strlen(buf) >= MAXSIZE)
- X {
- X fprintf(stderr, "cake: expansion result '%s' is too long\n", buf);
- X exit_cake(FALSE);
- X }
- X
- X stackp--;
- X leftbr_stack[stackp] = new_name(buf);
- X nextbr_stack[stackp] = NULL;
- X
- X /* start next iteration with the */
- X /* first character after the ]] */
- X s = leftbr_stack[stackp] + offset;
- X }
- X or (s[0] == '\\')
- X {
- X /* don't check next char */
- X if (s[1] != '\0')
- X s++;
- X }
- X }
- X
- X#ifdef CAKEDEBUG
- X if (entrydebug)
- X printf("after expand_cmds: [[%s]]\n", str);
- X#endif
- X
- X if (cmds <= 0)
- X {
- X put_trail("expand_cmds", "finish");
- X return str;
- X }
- X or (stackp == 0)
- X {
- X put_trail("expand_cmds", "finish");
- X return leftbr_stack[0];
- X }
- X
- X segcpy(buf, leftbr_stack[0], nextbr_stack[0]);
- X for (n = 1; n <= stackp; n++)
- X segcat(buf, leftbr_stack[n], nextbr_stack[n]);
- X
- X if (strlen(buf) >= MAXSIZE)
- X {
- X fprintf(stderr, "cake: expansion result '%s' is too long\n", buf);
- X exit_cake(FALSE);
- X }
- X
- X put_trail("expand_cmds", "finish");
- X return new_name(buf);
- X}
- X
- Xsegcpy(target, left, right)
- Xreg char *target, *left, *right;
- X{
- X reg int i;
- X reg char *s;
- X
- X if (right == NULL)
- X strcpy(target, left);
- X else
- X {
- X for (s = left, i = 0; s != right; s++, i++)
- X target[i] = *s;
- X
- X target[i] = '\0';
- X }
- X}
- X
- Xsegcat(target, left, right)
- Xreg char *target, *left, *right;
- X{
- X reg int i;
- X reg char *s;
- X
- X if (right == NULL)
- X strcat(target, left);
- X else
- X {
- X for (s = left, i = strlen(target); s != right; s++, i++)
- X target[i] = *s;
- X
- X target[i] = '\0';
- X }
- X}
- X
- X/*
- X** Execute the given command and return its output.
- X** It is a fatal error for the command to terminate abnormally.
- X*/
- X
- Xchar *
- Xget_output(cmd)
- Xreg char *cmd;
- X{
- X extern char *mktemp();
- X extern char *get_out();
- X extern char *flatten();
- X extern int cake_proc();
- X extern Wait cake_wait();
- X char buf[MAXSIZE];
- X Wait code;
- X reg char *out_filename;
- X reg FILE *fp;
- X reg int i, c;
- X reg int pid;
- X reg char *s, *result;
- X
- X put_trail("get_output", "start");
- X cdebug("get_output of [%s]\n", cmd);
- X
- X /* see if we have tried this command before */
- X if ((result = get_out(cmd)) != NULL)
- X {
- X cdebug("cache yields [%s]\n", result);
- X put_trail("get_output", "early finish");
- X return result;
- X }
- X
- X out_filename = get_newname();
- X pid = cake_proc(cmd, Exec, out_filename, (Node *) NULL, (int (*)()) NULL, (List *) NULL);
- X code = cake_wait(pid);
- X if (code.w_status != 0 && ! zflag)
- X {
- X printf("cake, %s: nonzero exit status\n", cmd);
- X exit_cake(FALSE);
- X }
- X
- X if ((fp = fopen(out_filename, "r")) == NULL)
- X {
- X sprintf(scratchbuf, "cake system error, fopen %s", out_filename);
- X perror(scratchbuf);
- X exit_cake(FALSE);
- X }
- X
- X /* convert the chars in file fp to a string */
- X i = 0;
- X while ((c = getc(fp)) != EOF)
- X buf[i++] = c;
- X
- X buf[i] = '\0';
- X fclose(fp);
- X if (MAXSIZE <= i)
- X {
- X printf("cake, %s: output too long\n", cmd);
- X exit_cake(FALSE);
- X }
- X
- X#ifndef LEAVE_DIR
- X cdebug("get_output unlink out_filename %s\n", out_filename);
- X if (unlink(out_filename) != 0)
- X {
- X sprintf(scratchbuf, "cake system error, unlink %s", out_filename);
- X perror(scratchbuf);
- X }
- X#endif
- X
- X /* save the result for posterity */
- X s = new_name(flatten(buf));
- X new_out(cmd, s);
- X cdebug("put result [%s] into cache\n", s);
- X put_trail("get_output", "finish");
- X return s;
- X}
- X
- X/*
- X** Flatten the output of commands by converting newlines to spaces
- X** and by removing blanks around the edges.
- X*/
- X
- Xchar *
- Xflatten(str)
- Xreg char *str;
- X{
- X reg char *s;
- X
- X /* convert newlines (and formfeeds) to spaces */
- X for (s = str; *s != '\0'; s++)
- X if (*s == '\n' || *s == '\f')
- X *s = ' ';
- X
- X /* remove blanks around the edges */
- X for (s = str+strlen(str)-1; str <= s && isspace(*s); s--)
- X *s = '\0';
- X for (s = str; *s != '\0' && isspace(*s); s++)
- X ;
- X
- X return s;
- X}
- SHAR_EOF
- if test 5774 -ne "`wc -c < 'expand.c'`"
- then
- echo shar: "error transmitting 'expand.c'" '(should have been 5774 characters)'
- fi
- fi
- echo shar: "extracting 'file.c'" '(12147 characters)'
- if test -f 'file.c'
- then
- echo shar: "will not over-write existing file 'file.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'file.c'
- X/*
- X** File system interface module.
- X*/
- X
- Xstatic char
- Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/file.c,v 1.14 86/07/19 12:23:08 zs Exp $";
- X
- X#include "cake.h"
- X#include <errno.h>
- X#include <sys/dir.h>
- X#include <sys/stat.h>
- X#ifndef ATT
- X#include <sys/time.h>
- X#endif
- X
- Xtypedef struct timeval Tval;
- Xtypedef struct timezone Tzone;
- Xtypedef struct stat Stat;
- Xtypedef struct direct Dirent;
- X
- Xextern int errno;
- X
- Xstatic char dir_name[30] = "/tmp/CakeXXXXXX";
- X
- X/*
- X** Create the directory to be used for all temporary storage.
- X*/
- X
- Xdir_start()
- X{
- X reg bool successful;
- X
- X mktemp(dir_name);
- X
- X#ifdef ATT
- X {
- X extern int cake_proc();
- X extern Wait cake_wait();
- X reg int pid;
- X Wait code;
- X
- X sprintf(scratchbuf, "mkdir %s", dir_name);
- X pid = cake_proc(new_name(scratchbuf), Exec, (char *) NULL,
- X (Node *) NULL, (int (*)()) NULL, (List *) NULL);
- X code = cake_wait(pid);
- X successful = code.w_status == 0;
- X }
- X#else
- X successful = mkdir(dir_name, 0700) == 0;
- X#endif
- X
- X if (! successful)
- X {
- X sprintf(scratchbuf, "cake system error, mkdir %s", dir_name);
- X perror(scratchbuf);
- X exit_cake(FALSE);
- X }
- X
- X#ifdef ATT
- X if (chmod(dir_name, 0700) != 0)
- X {
- X sprintf(scratchbuf, "cake system error, chmod 700 %s", dir_name);
- X perror(scratchbuf);
- X exit_cake(FALSE);
- X }
- X#endif
- X}
- X
- X/*
- X** Clean up /tmp when we are finished
- X*/
- X
- Xdir_finish()
- X{
- X#ifndef LEAVE_DIR
- X#ifdef ATT
- X extern int cake_proc();
- X extern Wait cake_wait();
- X reg int pid;
- X Wait code;
- X
- X sprintf(scratchbuf, "/bin/rm -fr %s", dir_name);
- X pid = cake_proc(new_name(scratchbuf), Exec, (char *) NULL,
- X (Node *) NULL, (int (*)()) NULL, (List *) NULL);
- X code = cake_wait(pid);
- X if (code.w_status != 0)
- X {
- X fprintf(stderr, "cake system error: cannot remove %s\n", dir_name);
- X return;
- X }
- X#else
- X char buf[1024];
- X reg DIR *dirp;
- X reg Dirent *dp;
- X reg int nameoffset;
- X
- X if ((dirp = opendir(dir_name)) == NULL)
- X {
- X sprintf(scratchbuf, "cake system error, opendir %s", dir_name);
- X perror(scratchbuf);
- X return;
- X }
- X
- X strcpy(buf, dir_name);
- X strcat(buf, "/");
- X nameoffset = strlen(buf);
- X
- X for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
- X if (strdiff(dp->d_name, ".") && strdiff(dp->d_name, ".."))
- X {
- X buf[nameoffset] = '\0';
- X strcat(buf, dp->d_name);
- X cdebug("dir_finish unlink %s\n", buf);
- X if (unlink(buf) != 0)
- X {
- X sprintf(scratchbuf, "cake system error, unlink %s", buf);
- X perror(scratchbuf);
- X }
- X }
- X
- X closedir(dirp);
- X
- X cdebug("rmdir %s\n", dir_name);
- X if (rmdir(dir_name) != 0)
- X {
- X sprintf(scratchbuf, "cake system error, rmdir %s", dir_name);
- X perror(scratchbuf);
- X }
- X#endif
- X#endif
- X}
- X
- X/*
- X** Get a new filename in our private directory.
- X** These files are used to store shell scripts
- X** and the output of actions.
- X**
- X** These names MUST be different from those generated
- X** by get_savename, so they have different prefixes.
- X*/
- X
- Xchar *
- Xget_newname()
- X{
- X char buf[100];
- X static int count = 0;
- X
- X ++count;
- X sprintf(buf, "%s/gen_%d", dir_name, count);
- X return new_name(buf);
- X}
- X
- X/*
- X** Save a nonvolatile file for later comparison.
- X** Any slashes in the filename are replaced by colons
- X** to avoid reference to nonexistent directories.
- X*/
- X
- Xsave_novol(node)
- Xreg Node *node;
- X{
- X char buf[MAXSIZE];
- X reg FILE *ifp, *ofp;
- X reg int c;
- X
- X if (nflag)
- X {
- X node->n_stime = node->n_rtime;
- X return;
- X }
- X
- X put_trail("save_novol", "start");
- X cdebug("saving %s\n", node->n_name);
- X node->n_stime = node->n_rtime;
- X
- X get_savename(node->n_name, buf);
- X if ((ifp = fopen(node->n_name, "r")) == NULL)
- X {
- X if (errno == ENOENT)
- X {
- X cdebug("%s does not exist, considered volatile\n", node->n_name);
- X reset_node(node, nf_NONVOL);
- X put_trail("save_novol", "finish");
- X return;
- X }
- X
- X sprintf(scratchbuf, "cake system error, fopen (r) %s", node->n_name);
- X perror(scratchbuf);
- X printf("cake: considering %s volatile\n", node->n_name);
- X reset_node(node, nf_NONVOL);
- X put_trail("save_novol", "finish");
- X return;
- X }
- X
- X if ((ofp = fopen(buf, "w")) == NULL)
- X {
- X sprintf(scratchbuf, "cake system error, fopen (w) %s", buf);
- X perror(scratchbuf);
- X printf("cake: considering %s volatile\n", node->n_name);
- X reset_node(node, nf_NONVOL);
- X put_trail("save_novol", "finish");
- X return;
- X }
- X
- X while ((c = getc(ifp)) != EOF)
- X putc(c, ofp);
- X
- X fclose(ifp);
- X fclose(ofp);
- X put_trail("save_novol", "finish");
- X}
- X
- X/*
- X** See if the given file has been changed since saved.
- X*/
- X
- Xbool
- Xdiff_novol(node)
- Xreg Node *node;
- X{
- X char buf[MAXSIZE];
- X reg FILE *i1fp, *i2fp;
- X reg int c;
- X reg bool diff;
- X
- X if (nflag)
- X return FALSE;
- X
- X put_trail("diff_novol", "start");
- X cdebug("comparing saved copy of %s: ", node->n_name);
- X
- X get_savename(node->n_name, buf);
- X if ((i1fp = fopen(node->n_name, "r")) == NULL)
- X {
- X sprintf(scratchbuf, "cake system error, fopen (r) %s", node->n_name);
- X perror(scratchbuf);
- X printf("cake: considering %s different\n", node->n_name);
- X reset_node(node, nf_NONVOL);
- X put_trail("diff_novol", "finish");
- X return TRUE;;
- X }
- X
- X if ((i2fp = fopen(buf, "r")) == NULL)
- X {
- X sprintf(scratchbuf, "cake system error, fopen (r) %s", buf);
- X perror(scratchbuf);
- X printf("cake: considering %s different\n", node->n_name);
- X reset_node(node, nf_NONVOL);
- X put_trail("diff_novol", "finish");
- X return TRUE;;
- X }
- X
- X diff = FALSE;
- X while ((c = getc(i1fp)) != EOF)
- X if (getc(i2fp) != c)
- X {
- X diff = TRUE;
- X break;
- X }
- X
- X if (getc(i2fp) != EOF)
- X diff = TRUE;
- X
- X fclose(i1fp);
- X fclose(i2fp);
- X cdebug("diff_novol unlink %s\n", buf);
- X if (unlink(buf) != 0)
- X {
- X sprintf(scratchbuf, "cake system error, unlink %s", buf);
- X perror(scratchbuf);
- X put_trail("diff_novol", "finish");
- X return TRUE;
- X }
- X
- X cdebug("%s\n", diff? "different": "same");
- X put_trail("diff_novol", "finish");
- X return diff;
- X}
- X
- X/*
- X** Get the the name of the saved copy of the given file.
- X*/
- X
- Xget_savename(name, buf)
- Xreg char *name;
- Xreg char buf[];
- X{
- X extern char *noslash();
- X
- X strcpy(buf, dir_name);
- X strcat(buf, "/save_");
- X strcat(buf, noslash(name));
- X}
- X
- X/*
- X** Remove any slashes from a filename.
- X*/
- X
- Xchar *
- Xnoslash(name)
- Xreg char *name;
- X{
- X char buf[MAXSIZE];
- X reg int i;
- X reg char *s;
- X
- X i = 0;
- X for (s = name; *s != '\0'; s++)
- X if (*s == '/')
- X buf[i++] = ':';
- X else
- X buf[i++] = *s;
- X
- X buf[i] = '\0';
- X return new_name(buf);
- X}
- X
- X/*
- X** Perform a stat on the given file. The only relevant info
- X** is the return code, indicating whether the file exists or not
- X** and its last modify (or status change) date. Note that if a
- X** file does not exist, it is by definition volatile. An aside
- X** considers all directories precious.
- X*/
- X
- Xnode_stat(node)
- Xreg Node *node;
- X{
- X extern int stat();
- X Stat statbuf;
- X
- X if (node->n_name != (char *) NULL && stat(node->n_name, &statbuf) == 0)
- X {
- X set_node(node, nf_EXIST);
- X if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
- X set_node(node, nf_PRECIOUS);
- X
- X node->n_rtime = cflag? statbuf.st_ctime: statbuf.st_mtime;
- X }
- X else
- X {
- X reset_node(node, nf_EXIST);
- X reset_node(node, nf_NONVOL);
- X node->n_rtime = GENESIS;
- X }
- X}
- X
- X/*
- X** Restore the previous stat of a nonvol file,
- X** both in the filesystem and in cake's memory.
- X** However, make sure that it will not need to be
- X** remade again and again to discover this anew
- X** while its ancestors remain the same.
- X*/
- X
- Xnode_resetstat(node)
- Xreg Node *node;
- X{
- X node_stat(node);
- X if (off_node(node, nf_EXIST))
- X return;
- X
- X cake_utimes(node, max(node->n_stime, node->n_utime));
- X node->n_utime = node->n_rtime;
- X}
- X
- X/*
- X** Set up the stat of a file as the latest ancestor's,
- X** both in the filesystem and in cake's memory.
- X*/
- X
- Xnode_setstat(node)
- Xreg Node *node;
- X{
- X extern time_t get_youngest();
- X reg time_t youngest;
- X
- X node_stat(node);
- X if (off_node(node, nf_EXIST))
- X return;
- X
- X youngest = get_youngest(node, FALSE);
- X if (youngest != node->n_utime && youngest != GENESIS)
- X {
- X fprintf(stderr, "cake internal error: youngest is mismatched for %s\n",
- X node->n_name);
- X exit_cake(TRUE);
- X }
- X
- X cake_utimes(node, node->n_utime);
- X}
- X
- X/*
- X** Return the time, converting formats.
- X*/
- X
- Xtime_t
- Xcake_gettime()
- X{
- X#ifdef ATT
- X extern long time();
- X long val;
- X
- X if (time(&val) == -1)
- X {
- X sprintf(scratchbuf, "cake system error, time");
- X perror(scratchbuf);
- X exit_cake(FALSE);
- X }
- X
- X return (time_t) val;
- X#else
- X Tzone tzone;
- X Tval tval;
- X
- X if (gettimeofday(&tval, &tzone) != 0)
- X {
- X sprintf(scratchbuf, "cake system error, gettimeofday");
- X perror(scratchbuf);
- X exit_cake(FALSE);
- X }
- X
- X return (time_t) tval.tv_sec;
- X#endif
- X}
- X
- X/*
- X** Issue the system call utimes after expanding its arguments
- X** from time_t to Tval. If the time given is GENESIS, use the
- X** current time instead.
- X*/
- X
- X#ifdef ATT
- Xtypedef struct utimbuf
- X{
- X time_t actime;
- X time_t modtime;
- X} Utimbuf;
- X#endif
- X
- Xcake_utimes(node, newtime)
- Xreg Node *node;
- Xtime_t newtime;
- X{
- X#ifdef ATT
- X extern int utime();
- X#else
- X extern int utimes();
- X#endif
- X extern int stat();
- X Stat statbuf;
- X#ifdef ATT
- X Utimbuf timbuf;
- X long vals[2];
- X#else
- X Tzone tzone;
- X Tval tvals[2];
- X#endif
- X
- X cdebug("resetting time for %s to %d, %s",
- X node->n_name, newtime, ctime(&newtime));
- X
- X#ifdef ATT
- X if (time(&vals[0]) == -1)
- X {
- X sprintf(scratchbuf, "cake system error, time");
- X perror(scratchbuf);
- X exit_cake(FALSE);
- X }
- X#else
- X if (gettimeofday(&tvals[0], &tzone) != 0)
- X {
- X sprintf(scratchbuf, "cake system error, gettimeofday");
- X perror(scratchbuf);
- X exit_cake(FALSE);
- X }
- X#endif
- X
- X if (newtime == GENESIS)
- X {
- X cdebug("reinterpreting GENESIS\n");
- X#ifdef ATT
- X if (time(&vals[1]) == -1)
- X {
- X sprintf(scratchbuf, "cake system error, time");
- X perror(scratchbuf);
- X exit_cake(FALSE);
- X }
- X#else
- X if (gettimeofday(&tvals[1], &tzone) != 0)
- X {
- X sprintf(scratchbuf, "cake system error, gettimeofday");
- X perror(scratchbuf);
- X exit_cake(FALSE);
- X }
- X#endif
- X }
- X else
- X {
- X#ifdef ATT
- X vals[1] = (long) newtime;
- X#else
- X tvals[1].tv_sec = newtime;
- X tvals[1].tv_usec = 0;
- X#endif
- X }
- X
- X#ifdef ATT
- X timbuf.actime = vals[0];
- X timbuf.modtime = vals[1];
- X node->n_rtime = vals[1];
- X#else
- X node->n_rtime = (time_t) tvals[1].tv_sec;
- X#endif
- X
- X if (nflag)
- X return;
- X
- X#ifdef ATT
- X if (utime(node->n_name, &timbuf) != 0)
- X#else
- X if (utimes(node->n_name, tvals) != 0)
- X#endif
- X {
- X sprintf(scratchbuf, "cake system error, utime(s) %s", node->n_name);
- X perror(scratchbuf);
- X fprintf(stderr, "cake: continuing\n");
- X }
- X
- X#ifdef CAKEDEBUG
- X if (cakedebug)
- X {
- X if (stat(node->n_name, &statbuf) != 0)
- X printf("cannot verify utimes\n");
- X else
- X {
- X print_time("accessed", statbuf.st_atime);
- X print_time("modified", statbuf.st_mtime);
- X print_time("changed ", statbuf.st_ctime);
- X }
- X }
- X#endif
- X}
- X
- X/*
- X** See if the given file exists.
- X*/
- X
- Xbool
- Xexist(name)
- Xreg char *name;
- X{
- X Stat statbuf;
- X
- X if (stat(name, &statbuf) == 0)
- X return TRUE;
- X else
- X return FALSE;
- X}
- X
- X/*
- X** Remove the given file.
- X*/
- X
- Xcake_remove(name)
- Xreg char *name;
- X{
- X#ifdef CAREFUL
- X if (! Xflag)
- X {
- X extern int getpid();
- X extern int cake_proc();
- X extern Wait cake_wait();
- X extern char *noslash();
- X reg int pid, cakepid;
- X Stat statbuf;
- X Wait code;
- X char buf[80];
- X
- X#ifndef ATT
- X if (lstat(name, &statbuf) != 0)
- X {
- X sprintf(scratchbuf, "cake system error, lstat %s", name);
- X perror(scratchbuf);
- X fprintf(stderr, "cake: continuing\n");
- X return;
- X }
- X
- X if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
- X {
- X printf("removing the symbolic link %s\n", name);
- X cdebug("cake_remove unlink %s\n", name);
- X if (unlink(name) != 0)
- X {
- X sprintf(scratchbuf, "cake system error, unlink %s", name);
- X perror(scratchbuf);
- X fprintf(stderr, "cake: continuing\n");
- X }
- X
- X return;
- X }
- X#endif
- X
- X cakepid = getpid();
- X printf("moving %s to /tmp\n", name);
- X sprintf(buf, "mv %s /tmp/%s.%d", name, noslash(name), cakepid);
- X pid = cake_proc(buf, Exec, (char *) NULL, (Node *) NULL,
- X (int (*)()) NULL, (List *) NULL);
- X code = cake_wait(pid);
- X if (code.w_status != 0)
- X {
- X fprintf(stderr, "cake system error: '%s' failed\n", buf);
- X fprintf(stderr, "cake: continuing\n");
- X return;
- X }
- X
- X sprintf(buf, "/tmp/%s.%d", noslash(name), cakepid);
- X if (chmod(buf, 0600) != 0)
- X {
- X sprintf(scratchbuf, "cake system error, chmod %s", buf);
- X perror(scratchbuf);
- X fprintf(stderr, "cake: continuing\n");
- X return;
- X }
- X
- X return;
- X }
- X#endif
- X
- X cdebug("cake_remove unlink %s\n", name);
- X if (unlink(name) != 0)
- X {
- X sprintf(scratchbuf, "cake system error, unlink %s", name);
- X perror(scratchbuf);
- X fprintf(stderr, "cake: continuing\n");
- X }
- X}
- SHAR_EOF
- if test 12147 -ne "`wc -c < 'file.c'`"
- then
- echo shar: "error transmitting 'file.c'" '(should have been 12147 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-